// pc版的 基于canvas的 签名
export default class Signature {
    #points = []  // 路径集合
    #canvas = null  // canvas元素
    #canvasParentElement = null  // canvas元素的父元素
    #ctx = null // 画笔
    #paintWidth = 2 // 画笔宽度
    #mobile = true // 是否是移动端
    #paintColor = 'black' // 画笔颜色
    #paintLineCaP = 'round' // 画笔端点形状 (butt: 默认值，端点是垂直于线段边缘的平直边缘) (round：端点是在线段边缘处以线宽为直径的半圆) (square：端点是在选段边缘处以线宽为长、以一半线宽为宽的矩形。)
    #top = 0
    #left = 0
    #id = 0 // 每次绘制的id  为了清除上一次绘制
    #record = [] // 绘制线记录
    constructor(elementId, params = { lineWidth: 2, lineColor: 'black', lineCap: 'round', mobile: false }) {
      let T = this
      T.#paintWidth = params.lineWidth ? params.lineWidth : T.#paintWidth
      T.#paintColor = params.lineColor ? params.lineColor : T.#paintColor
      T.#paintLineCaP = params.lineCap ? params.lineCap : T.#paintLineCaP
      T.#canvas = document.getElementById(elementId)
      T.#init(T)
      T.#mouseDown(T)
      T.#mouseUp(T)
      // 监听视口变化
      T.#resize(T)
      // 监听父元素变化
      T.#parentChange(T)
    }
  
    #resize = (T) => {
      window.addEventListener('resize', () => {
        T.#ctx.clearRect(0, 0, T.#canvas.width, T.#canvas.height)
        T.#points = []
        T.#record = []
        T.#init(T)
      })
    }
  
    #parentChange = (T) => {
      let timer = null
      let ob = new ResizeObserver((entries) => {
        console.log(111111, T.#canvasParentElement)
        if(timer) clearTimeout(timer)
        timer = setTimeout(() => {
          T.#ctx.clearRect(0, 0, T.#canvas.width, T.#canvas.height)
          T.#points = []
          T.#record = []
          T.#init(T)
        }, 40)
        
      }).observe(T.#canvasParentElement)
    }
  
    #init = (T) => {
      T.#canvasParentElement = T.#canvas.parentElement
      T.#canvas.width = T.#canvasParentElement.getBoundingClientRect().width
      T.#canvas.height = T.#canvasParentElement.getBoundingClientRect().height
      T.#ctx = T.#canvas.getContext('2d')  //获取绘制画笔
      T.#top = T.#canvas.getBoundingClientRect().top
      T.#left = T.#canvas.getBoundingClientRect().left
    }
  
    // 鼠标按下事件
    #mouseDown = (T) => {
      T.#canvas.addEventListener(T.#mobile ? 'touchstart' : 'mousedown', e => {
        T.#id++
        const clientX = T.#mobile ? e.changedTouches[0].clientX : e.clientX
        const clientY = T.#mobile ? e.changedTouches[0].clientY : e.clientY
        let startX = clientX - T.#left;
        let startY = clientY - T.#top;
        let startPoint = {
          X: startX,
          Y: startY,
          id: T.#id
        }
        T.#points.push(startPoint)
        T.#record.push(startPoint)
        T.#ctx.beginPath()
        T.#ctx.lineWidth = T.#paintWidth
        T.#ctx.strokeStyle = T.#paintColor
        T.#ctx.lineCap = T.#paintLineCaP
        T.#mouseMove(T)
      })
    }
  
    #mouseUp = (T) => {
      T.#canvas.addEventListener(T.#mobile ? 'touchend' : 'mouseup', () => {
        T.#points = []
        T.#canvas.removeEventListener(T.#mobile ? 'touchmove' : 'mousemove', T.#moveFn)
      })
  
      T.#canvas.addEventListener(T.#mobile ? 'touchcancel' : 'mouseleave', () => {
        T.#points = []
        T.#canvas.removeEventListener(T.#mobile ? 'touchmove' : 'mousemove', T.#moveFn)
      })
    }
  
    // 鼠标移动事件
    #mouseMove = (T) => {
      let fn = (e) => {
        const clientX = T.#mobile ? e.changedTouches[0].clientX : e.clientX
        const clientY = T.#mobile ? e.changedTouches[0].clientY : e.clientY
        let moveX = clientX - T.#left;
        let moveY = clientY - T.#top;
        let movePoint = {
          X: moveX,
          Y: moveY,
          id: T.#id
        }
        T.#points.push(movePoint)
        T.#record.push(movePoint)
        let len = T.#points.length
        if (len >= 2) {
          T.#draw(T) // 绘制线
        }
      }
      T.#canvas.addEventListener(T.#mobile ? 'touchmove' : 'mousemove', fn)
      T.#moveFn = fn
    }
  
    #moveFn = () => {}
  
    #draw = (T) => {
      let point1 = T.#points[0]
          let point2 = T.#points[1]
          T.#points.shift()
          T.#ctx.moveTo(point1.X, point1.Y)
          T.#ctx.lineTo(point2.X, point2.Y)
          T.#ctx.stroke()
    }
  
    // 清除画布的钩子
    clear = () => {
      this.#ctx.clearRect(0, 0, this.#canvas.width, this.#canvas.height)
      this.#record = []
    }
  
    // 清除上一步
    back = () => {
      if(this.#record.length === 0) return
      let lastId = this.#record[this.#record.length - 1].id
      // 再绘制
      this.#record = this.#record.filter(item => item.id !== lastId)
      // 先清除
      this.#ctx.clearRect(0, 0, this.#canvas.width, this.#canvas.height)
      this.#ctx.beginPath()
      this.#record.reduce((prev, curr) => {
        // console.log(prev, curr);
        if(prev.id !== curr.id){
          this.#ctx.beginPath()
        }else{
          this.#ctx.moveTo(prev.X, prev.Y)
          this.#ctx.lineTo(curr.X, curr.Y)
          this.#ctx.stroke()
        }
        return curr
      }, this.#record[0])
    }
  
    // 导出为base64
    toBase64 = () => {
      if(this.#record.length === 0) return '您还没有签名!!'
      let tempSrc = this.#canvas.toDataURL("image/png");
      return tempSrc
    }
  
    // 导出为文件流
    toFile = (fileName = 'toFile') => {
      if(this.#record.length === 0) return '您还没有签名!!'
      let tempSrc = this.#canvas.toDataURL("image/png");
      const dataArr = tempSrc.split(",");
      const byteString = atob(dataArr[1]);
      const options = {
        type: "image/jpeg",
        endings: "native"
      };
      const u8Arr = new Uint8Array(byteString.length);
      for (let i = 0; i < byteString.length; i++) {
        u8Arr[i] = byteString.charCodeAt(i);
      }
      return new File([u8Arr], fileName + ".jpg", options);//返回文件流
    }
  }